import json,collections
import math,re

class HandleRequest:
    def __init__(self, message, queryAPI, idocument):
        self.message = message
        self.queryAPI = queryAPI
        self.idocument = idocument
        self.fail = False
        self.failmsg = ""
        self._JsonMessage()

    def Handle(self):
        if self.fail:
            return self.failmsg
        else:
            handleArray = [
                self._HandleSpace,
                self._HandleInput,
                self._HandleAttrs,
                self._HandleItem,
                self._HandleInWeight,
                self._HandleQuery,
                self._HandleUnionWeight,
                self._HandleCalratio,
                self._HandleWeight,
                self._HandleFilterWithEveryDimension,
                #self._HandleFilterWithDropdup,
                self._HandleFilterWithNumOfTag,
                self._HandleSourceIdsOrWeight,
                self._HandleArray,
                self._HandleNormal
            ]
            for action in handleArray:
                action()
            return self.result

    def _JsonMessage(self):
        if type(self.message) == type(""):
            try:
                self.JsonData = json.loads(self.message)
            except Exception as e:
                self.JsonData = {}
                self.fail = True
                self.failmsg= "报文格式错误:" + str(e)
        else:
            self.JsonData = self.message

    # 解析space
    def _HandleSpace(self):
        key = "space"
        self.space = self.JsonData.get(key, '')


    # 解析input
    def _HandleInput(self):
        self.input = []
        key = "input"
        if key in self.JsonData:
            array = self.JsonData[key].split("|")
            for a in array:
                if a and type(a) == type("") and a != "":
                    self.input.append(a)

    # 解析attr
    def _HandleAttrs(self):
        self.attrs = []
        key = "attr"
        if key in self.JsonData:
            _attrs = self.JsonData [key].split(",")
            for _attr in _attrs:
                if not _attr or _attr == "":
                    continue
                if _attr.find("^") == -1:
                    self.attrs.append((_attr, 1))
                else:
                    _array = _attr.split("^")
                    _akey,_aval = _array [0],1
                    try:
                        _aval = _array[1]
                        _aval = int(_aval)
                    except:
                        _aval = 1
                    if _aval < 1:
                        _aval = 1

                    self.attrs.append((_akey, _aval))

    # 解析item
    def _HandleItem(self):
        self.item = []
        key = "item"
        if key in self.JsonData:
            array = self.JsonData [key].split("|")
            for a in array:
                if a and type(a) == type("") and a != "":
                    self.item.append(a)


    # 查询结果
    def _HandleQuery(self):
        self.result,ktResult = self.queryAPI (self.space, self.input, self.attrs, self.item)
        self.catgoryAPI = lambda x: ktResult[x]

    # 筛选
    def _HandleFilterWithEveryDimension(self):
        key = "edimension"
        keyOther = "dropdup"
        if key not in self.JsonData and keyOther not in self.JsonData:
            return
        try:
            normalNum = int(self.JsonData.get(keyOther))
        except:
            normalNum = 15
        val = self.JsonData.get(key)
        valDic = {}
        if val is not None and val != "":
            array = val.split(',')
            for ar in array:
                if ar is None or ar == "":
                    continue
                kvs = ar.split ("^")
                k= kvs [0]
                v = 1
                try:
                    v = kvs[1]
                    v = int(v)
                except:
                    v = 1
                valDic [k] = v

        for key,val in self.result.items():
            dic = {}
            for k,v in val.items():
                catgory = self.catgoryAPI(k)
                if catgory is None or catgory == "":
                    continue
                if catgory in dic:
                    dic[catgory].append((k, v))
                else:
                    dic[catgory] = [(k, v)]
            ret = []
            for k,v in dic.items():
                temp = sorted(v, key=lambda x: x[1], reverse=True)
                if k not in valDic:
                    num = min(normalNum, len(temp))
                else:
                    num = min(valDic [k], len(temp))
                temp = temp[0: num]
                ret += temp
            self.result[key] = dict(ret)

    # 筛选
    def _HandleFilterWithDropdup(self):
        key = "dropdup"
        if key not in self.JsonData:
            return

        droupupNum = self.JsonData [key]
        try:
            droupupNum = int (droupupNum)
        except:
            droupupNum = 1

        for key,val in self.result.items():
            dic = {}
            for k,v in val.items():
                catgory = self.catgoryAPI(k)
                if catgory is None or catgory == "":
                    continue
                if catgory in dic:
                    dic[catgory].append((k, v))
                else:
                    dic[catgory] = [(k, v)]
            ret = []
            for k,v in dic.items():
                temp = sorted(v, key=lambda x: x[1], reverse=True)
                temp = temp[0: min(droupupNum, len(temp))]
                ret += temp
            self.result[key] = dict(ret)

    # 筛选
    def _HandleFilterWithNumOfTag(self):
        key = "numoftag"
        if key not in self.JsonData:
            return
        num = self.JsonData [key]
        try:
            num = int(num)
        except:
            num = 10
        for ikey,ival in self.result.items():
            array = list(ival.items())
            array = sorted(array, key=lambda x: x[1], reverse=True)
            array = array [0:min(num, len(array))]
            self.result[ikey] = dict(array)

    # 加权query attr
    def _HandleInWeight(self):
        key = "inweight"
        if key not in self.JsonData:
            return
        val = self.JsonData [key]
        dic = dict(self.attrs)
        try:
            for item in val.split(","):
                if not item or item == "":
                    continue
                array = item.split("^")
                k = array[0].strip()
                v = 0
                if len(array) == 2:
                    v = array[1]
                    try:
                        v = int(v)
                    except:
                        v = 0

                if k in dic:
                    dic[k]+=v
        except:
            pass

        self.result = dic.items()

    # 同时出现加权
    def _HandleUnionWeight(self):
        key = "or"
        if key not in self.JsonData:
            return
        dic = {}
        for ikey,ival in self.result.items():
            for k,v in ival.items():
                if k in dic:
                    dic[k]+=1
                else:
                    dic[k]=1
        for ikey,ival in self.result.items():
            for k,v in ival.items():
                if k not in dic:
                    continue
                w = dic[k]
                ival[k] *= w

    # 加权result attr
    def _HandleWeight(self):
        key = "weight"
        if key not in self.JsonData:
            return
        val = self.JsonData [key]
        if not val or val == "":
            return

        try:
            for item in val.split(","):
                array = item.split("^")
                k = array[0]
                v = 1
                if len(array) == 2:
                    try:
                        v = array[1]
                        v = int(v)
                    except:
                        v = 1
                for _key,_val in self.result.items():
                    for _k,_v in _val.items():
                        catgory = self.catgoryAPI(_k)
                        if catgory == k:
                            _val[_k] *= v
        except:
            pass

    # weight转换到某个区间
    def _HandleCalratio(self):
        key = "calratio"
        if key not in self.JsonData:
            return
        val = self.JsonData [key]
        try:
            val = int(val)
        except:
            val = 100
        for ikey,ival in self.result.items():
            dic,kdic = {},{}
            for k,v in ival.items():
                c = self.catgoryAPI(k)
                if c is None:
                    continue
                if c in dic:
                    dic[c] += v
                else:
                    dic[c] = v
                kdic[k] = c
            for k,v in ival.items():
                if k not in kdic:
                    continue
                c = kdic[k]
                if c not in dic:
                    continue
                wv = dic[c]
                ival[k] = round(v/wv*val)

    # 替换weight成ids
    def _HandleSourceIdsOrWeight(self):
        key = "source"
        if key not in self.JsonData:
            return
        val = self.JsonData.get (key, "l,r")
        if val == "":
            val = "l,r"
        valArray = val.split(',')
        for ikey,ival in self.result.items():
            for k,v in ival.items():
                try:
                    sourceString = ""
                    for va in valArray:
                        sourceKey = "{0}_{1}_{2}".format(ikey, k, va)
                        source = self.catgoryAPI(sourceKey)
                        if sourceString == "":
                            sourceString = ",".join(source)
                        else:
                            sourceString += "|" + ",".join(source)
                    ival[k]=sourceString
                except Exception as e:
                    print(e)

    def _HandleArray(self):
        key = "array"
        if key not in self.JsonData:
            return
        for ikey,ival in self.result.items():
            dic = collections.OrderedDict()
            array = sorted(ival.items(), key=lambda x:x[1], reverse=True)
            for k,v in array:
                c = self.catgoryAPI(k)
                if not c or c == "":
                    continue
                if c not in dic:
                    dic [c] = collections.OrderedDict()
                if k.find("b'") != -1:
                    k = k.replace("b'", "")
                    k = k.replace("'", "")
                dic[c][k]=v
            self.result[ikey] = dic

    def _HandleNormal(self):
        key = "array"
        if key in self.JsonData:
            return
        for ikey,ival in self.result.items():
            array = sorted(ival.items(), key=lambda x: x[1], reverse=True)
            tarray = []
            for item in array:
                k = item [0]
                if k.find("b'") != -1:
                    k = k.replace("b'", "")
                    k = k.replace("'", "")
                    tarray.append((k, item[1]))
                else:
                    tarray.append(item)
            self.result[ikey] = collections.OrderedDict(tarray)
